/*------------------ PhanTom -----------------*/
/*Kịch bản 1: 1 Quản lý xem danh sách Khuyến mãi, thì 1 Quản lý khác thêm 1 Khuyến mãi
sql => ok
ứng dụng => ok
*/
create proc sp_SelectKhuyenMaiByMaMonAn
	@Ma_MonAn nchar(3),
	@soKM int out

as
begin tran
	--set tran isolation level repeatable read  /*Demo Unrepeatable read 1*/
	--set tran isolation level serializable /*Demo PhanTom 1*/
	set @soKM = (select count(*) from KhuyenMai WHERE Ma_MonAn=@Ma_MonAn)

	waitfor delay '0:0:03'
	SELECT Ma_KhuyenMai,Ma_MonAn,PhanTramGiam,NgayBatDau,NgayKetThuc FROM KhuyenMai WHERE Ma_MonAn=@Ma_MonAn
commit tran
go


ALTER PROCEDURE [dbo].[sp_InsertKhuyenMai]
	@Ma_KhuyenMai nchar (3),
	@Ma_MonAn nchar (3),
	@PhanTramGiam int,
	@NgayBatDau datetime,
	@NgayKetThuc datetime
AS
BEGIN TRAN
	DECLARE  @NBD datetime
	DECLARE @NKT datetime
	DECLARE @cur CURSOR
	DECLARE @FLAG int
	SET @FLAG=0
	SET @cur= CURSOR FOR (SELECT NgayBatDau,NgayKetThuc FROM KhuyenMai WHERE Ma_MonAn=@Ma_MonAn)
	OPEN @CUR
	FETCH NEXT FROM @cur INTO @NBD,@NKT
	WHILE @@fetch_status = 0
	BEGIN
		IF((@NgayBatDau between @NBD and @NKT)OR (@NgayKetThuc between @NBD and @NKT) OR ((@NBD between @NgayBatDau and @NgayKetThuc) and (@NKT between @NgayBatDau and @NgayKetThuc)) )
		BEGIN
				SET @FLAG=1
		END
		
		FETCH NEXT FROM @cur INTO @NBD,@NKT
	END
	
	
	IF(@FLAG=0)
	BEGIN
		INSERT INTO KhuyenMai VALUES(@Ma_KhuyenMai,@Ma_MonAn,@PhanTramGiam,@NgayBatDau,@NgayKetThuc)
	END
COMMIT TRAN

--tran 1:
declare @soKM int
declare @Ma_MonAn nchar(3)
set @soKM =0
EXEC sp_SelectKhuyenMaiByMaMonAn '005',@soKM out
select @soKM

--tran 2:
EXEC sp_InsertKhuyenMai '019','005',50,'2013-10-11 00:00:00.000','2013-010-11 00:00:00.000'



/*------------------ Unrepeatable read -----------------*/
/*Kịch bản 2: 1 Quản lý đang xem danh sách Món ăn, thì 1 Quản lý khác cập nhật 1 món ăn trong danh sách món ăn này
*/
alter proc sp_SelectMonAnAll @tongmonan int out
as
	begin tran
		--set tran isolation level repeatable read
		begin try
			set @tongmonan = (select count(Ma_Mon)
								from MonAn)
			waitfor delay '0:0:05'
			
			select ma.Ma_Mon,ma.TenMon,ma.Loai, ma.GiaTien
			from MonAn ma
		end try
		begin catch
			declare @ErrorMsg varchar(2000)
			select @ErrorMsg = N'Lỗi: ' + ERROR_MESSAGE()
			raiserror(@ErrorMsg, 16,1)
			rollback tran
			return
		end catch
		
	commit tran
go

alter proc sp_UpdateMonAnById
	@maMon nchar(3),
	@tenMon	nvarchar(50),
	@loai nchar(3),
	@giaTien float
as
	begin tran
		Update MonAn
		set TenMon=@tenMon,Loai=@loai,GiaTien=@giaTien
		where Ma_Mon=@maMon
	commit tran
go

--tran 1:
declare @tongmonan int
set @tongmonan =0
select * from monAn
exec sp_SelectMonAnAll @tongmonan out
select @tongmonan

--tran 2:
exec sp_UpdateMonAnById '006',N'bánh khọt','002',30000



/*Kịch bản 1: 1 Quản lý đang xem danh sách Khuyến mại, thì 1 Quản lý khác cập nhật 1 khuyến mại trong danh sách khuyến mại này
	=> KHÔNG THỂ KHAI TRIỂN TRÊN CHƯƠNG TRÌNH VÌ KHÔNG THỂ(không có lý do) XEM 2 LẦN
*/
CREATE PROCEDURE sp_SelectKhuyenMaiAll @soKM int out
AS
BEGIN
BEGIN TRAN
	--set tran isolation level repeatable read
	set @soKM = (select count(*) from KhuyenMai)

	waitfor delay '0:0:04'
	SELECT Ma_KhuyenMai,Ma_MonAn,PhanTramGiam,NgayBatDau,NgayKetThuc FROM KhuyenMai
	
COMMIT TRAN
END

CREATE PROCEDURE sp_UpdateKhuyenMaiById
	@Ma_KhuyenMai nchar (3),
	@Ma_MonAn nchar (3),
	@PhanTramGiam int,
	@NgayBatDau datetime,
	@NgayKetThuc datetime
AS
BEGIN
BEGIN TRAN
	Update KhuyenMai SET Ma_MonAn=@Ma_MonAn,PhanTramGiam=@PhanTramGiam,NgayKetThuc=@NgayKetThuc,NgayBatDau=@NgayBatDau WHERE Ma_KhuyenMai=@Ma_KhuyenMai
COMMIT TRAN
END

--tran 1:
declare @soKM int
set @soKM =0
select * from KhuyenMai
EXEC sp_SelectKhuyenMaiAll @soKM out
select @soKM


--tran 2:
EXEC sp_UpdateKhuyenMaiById '001','005',50,'2013-05-30 00:00:00.000','2013-06-30 00:00:00.000'

/*Kịch bản 3: 1 Quản lý đang xem danh sách Khuyến mại, thì 1 Quản lý khác cập nhật 1 khuyến mại trong danh sách khuyến mại này
 sql=> ok
 ứng dụng => ok	
*/
alter proc sp_SelectKhuyenMaiByMaMonAn
	@Ma_MonAn nchar(3),
	@soKM int out

as
begin tran
	--set tran isolation level repeatable read
	set @soKM = (select count(*) from KhuyenMai WHERE Ma_MonAn=@Ma_MonAn)

	waitfor delay '0:0:05'
	SELECT Ma_KhuyenMai,Ma_MonAn,PhanTramGiam,NgayBatDau,NgayKetThuc FROM KhuyenMai WHERE Ma_MonAn=@Ma_MonAn
commit tran
go

CREATE PROCEDURE sp_UpdateKhuyenMaiById
	@Ma_KhuyenMai nchar (3),
	@Ma_MonAn nchar (3),
	@PhanTramGiam int,
	@NgayBatDau datetime,
	@NgayKetThuc datetime
AS
BEGIN
BEGIN TRAN
	Update KhuyenMai SET Ma_MonAn=@Ma_MonAn,PhanTramGiam=@PhanTramGiam,NgayKetThuc=@NgayKetThuc,NgayBatDau=@NgayBatDau WHERE Ma_KhuyenMai=@Ma_KhuyenMai
COMMIT TRAN
END

--tran 1:
declare @soKM int
declare @Ma_MonAn nchar(3)
set @soKM =0
EXEC sp_SelectKhuyenMaiByMaMonAn '005',@soKM out
select @soKM

--tran 2:
EXEC sp_UpdateKhuyenMaiById '003','014',50,'2013-09-30 00:00:00.000','2013-010-30 00:00:00.000'



/*------------------ Deadlock -----------------*/
/*Kịch bản 1: 2 Quản lý cùng xem danh sách Khuyến mãi, và thêm 1 khuyến mãi
sql =>ok=>ko lam demo
*/
alter PROCEDURE sp_InsertKhuyenMai
	@Ma_KhuyenMai nchar (3),
	@Ma_MonAn nchar (3),
	@PhanTramGiam int,
	@NgayBatDau datetime,
	@NgayKetThuc datetime
AS
BEGIN TRAN
	--SET TRAN ISOLATION LEVEL SERIALIZABLE
	DECLARE  @NBD datetime
	DECLARE @NKT datetime
	DECLARE @cur CURSOR
	DECLARE @FLAG int
	SET @FLAG=0
	SET @cur= CURSOR FOR (SELECT NgayBatDau,NgayKetThuc FROM KhuyenMai /*with (Xlock)*/ WHERE Ma_MonAn=@Ma_MonAn)
	OPEN @CUR
	FETCH NEXT FROM @cur INTO @NBD,@NKT
	WHILE @@fetch_status = 0
	BEGIN
		IF((@NgayBatDau between @NBD and @NKT)OR (@NgayKetThuc between @NBD and @NKT) OR ((@NBD between @NgayBatDau and @NgayKetThuc) and (@NKT between @NgayBatDau and @NgayKetThuc)) )
		BEGIN
				SET @FLAG=1
		END
		
		FETCH NEXT FROM @cur INTO @NBD,@NKT
	END
	
	waitfor delay '0:0:05'

	IF(@FLAG=0)
	BEGIN
		INSERT INTO KhuyenMai VALUES(@Ma_KhuyenMai,@Ma_MonAn,@PhanTramGiam,@NgayBatDau,@NgayKetThuc)
	END
COMMIT TRAN 



--tran 1:
EXEC sp_InsertKhuyenMai '016','006',10,'2013-07-03 00:00:00.000','2013-07-09 00:00:00.000'

--tran 2:
EXEC sp_InsertKhuyenMai '015','004',10,'2013-07-03 00:00:00.000','2013-07-09 00:00:00.000'


--DELETE FROM KHUYENMAI WHERE MA_KHUYENMAI='016'
--DELETE FROM KHUYENMAI WHERE MA_KHUYENMAI='015'



/*Kịch bản 2: 2 Quản lý cùng xem danh sách Món ăn, và thêm 1 món ăn
sql=>ok ungdung=>ok
*/
alter proc sp_InsertMonAn
@maMon nchar(10),
	@tenMon	nvarchar(50),
	@loai nchar(10),
	@giaTien float
as
begin tran
	SET TRAN ISOLATION LEVEL SERIALIZABLE
	declare @SL int
	select @SL =count(*) from MonAn /**/with (Xlock) where TenMon = @tenMon 

	waitfor delay '0:0:03'
	if (@SL = 0)
		Begin
			Insert into MonAn(Ma_Mon,TenMon,Loai, GiaTien)
			Values (@maMon ,@tenMon	,@loai,@giaTien)
		End
commit tran
go

--tran 1:
exec sp_InsertMonAn N'030',N'bò nhúng dấm',N'002',50000

--tran 2:
exec sp_InsertMonAn '032',N'bò né','002',45000
insert into MonAn values('033',N'bò bu','002',30000)